package cn.wolfcode.rbac.web.interceptor;

import cn.wolfcode.rbac.domain.Employee;
import cn.wolfcode.rbac.utils.R;
import cn.wolfcode.rbac.utils.RedisUtils;
import cn.wolfcode.rbac.web.annotation.RequiredPermission;
import com.alibaba.fastjson.JSON;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Set;

import static cn.wolfcode.rbac.common.RedisKeyPrefix.EMPLOYEE_EXPRESSION_PREFIX;
import static cn.wolfcode.rbac.common.RedisKeyPrefix.LOGIN_EMPLOYEE_PREFIX;

/**
 * 权限拦截器
 */
//@Component
public class CheckPermissionInterceptor extends HandlerInterceptorAdapter {

    @Autowired
    private RedisUtils redisUtils;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        /**
         * 这是因为浏览器会发送一个预请求，看服务器是否支持跨域，
         * 如果支持才会发送真实请求， 但是在发送预请求的时候是不会携带 userId， 所以在拦截器中过不去
         * 如果是预请求我们就放行，预请求的handler类型不是 HandlerMethod。
         */
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        //1.获取用户访问的权限
        //判断方法上是否贴有该权限注解
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        RequiredPermission methodAnnotation = handlerMethod.getMethodAnnotation(RequiredPermission.class);
        //如果没有贴该权限注解,则放行
        if(methodAnnotation == null){
            return true;
        }
        //2.从请求头获取用户的id
        String userId = request.getHeader("userId");

        //3.判断是否是超级管理员,是超级管理员就放行
        //从redis中获取用户的信息,判断是否是管理员,不从数据库中获取而从redis中获取，减少IO操作，选择操作内容，提高性能
        Employee employee = JSON.parseObject(redisUtils.get(LOGIN_EMPLOYEE_PREFIX + userId), Employee.class);
        if (employee.getAdmin()) {
            return true;
        }

        //4.从缓存中获取该用户的所有权限
        List<String> expressions = JSON.parseArray(redisUtils.get(EMPLOYEE_EXPRESSION_PREFIX + userId), String.class);
        //如果有贴该权限注解,则判断用户是否有该权限
        //判断用户是否有该权限,没有该权限，则响应提示 403 没有权限
        if (expressions == null ||
                !expressions.contains(methodAnnotation.expression())) {
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(JSON.toJSONString(R.fail(403,"没有该权限")));
            return false;
        }
        //有该权限则放行
        return true;
    }
}
